﻿using System.Collections.Generic;
using System.Xml;
using System.Configuration;

namespace SdmxMl.Common
{
    public class TextCompression
    {
        /// <summary> 
        /// When text found with no language specified, if true uses it in all defined languages.
        /// If false, set english only (as defined in SDMX)</summary>
        public static bool Expand { get; private set; }

        /// <summary>
        /// When text is same in all supported languages, if true serialize it with no language specified.
        /// If false write it for all supported languages
        /// </summary>
        public static bool Compress { get; private set; }

        static TextCompression()
        {
            string configTag = "TextLang";
            // Default if nothing specified
            Expand = Compress = true;

            if (ConfigurationManager.AppSettings[configTag] != null)
            {
                string desired = ConfigurationManager.AppSettings[configTag].Trim().ToLower();
                switch (desired)
                {
                    case "expand":
                        Expand = true; Compress = false;
                        break;
                    case "strict":
                        Expand = false; Compress = false;
                        break;
                    case "compress":
                        Expand = false; Compress = true; // seems of no use but..
                        break;
                    case "dual":
                    default:
                        Expand = true; Compress = true;
                        break;
                }
            }
        }

        #region private C'tor

        private TextCompression()
        {
        }

        #endregion
}


    /// <summary> Internationalized text class </summary>
    public class MultiLang
    {
        #region Undefined text

        // To materialize an empty text
        public static string UndefinedText = ""; //"Text n. def.";

        #endregion

        #region Construction

        public MultiLang()
        {
            listText = new List<TextType>();
        }

        public MultiLang(MultiLang other)
        {
            listText = new List<TextType>();
            foreach (TextType tt in other.TextList)
                listText.Add(new TextType(tt));
        }

        /// <summary>Construct for all languages with same text </summary>
        /// <param name="textAllLanguage">common text</param>
        public MultiLang(string textAllLanguage)
        {
            listText = new List<TextType>();
            UpdateDefaultText(textAllLanguage);
        }

        public MultiLang Clone()
        {
            MultiLang ml = new MultiLang();
            foreach (TextType t in listText)
                ml.TextList.Add(new TextType(t.Language, t.Text));
            return ml;
        }

        #endregion // Construction

        #region Properties

        private List<TextType> listText;
        public List<TextType> TextList
        {
            get { return listText; }
            set { listText = value; }
        }
        /// <summary>Check if more than one language and differents content for each text</summary>
        /// <returns>True if different texts</returns>
        public bool IsInternationalized
        {
            get
            {
                bool inter = IsEmpty == false && listText.Count > 1;
                if (inter)
                    inter = AllSame == false;
                return inter;
            }
        }

        /// <summary>True if all defined text are empty</summary>
        public bool IsEmpty
        {
            get
            {
                bool empty = true;
                foreach (TextType t in listText)
                {
                    if (t.Text != string.Empty)
                    {
                        empty = false;
                        break;
                    }
                }
                return empty;
            }
        }

        /// <summary>True if all defined text are same</summary>
        public bool AllSame
        {
            get
            {
                bool same = false;
                if (listText.Count > 1)
                {
                    same = true;
                    for (int i = 1; i < listText.Count; i++)
                    {
                        if (listText[i - 1].Text != listText[i].Text)
                        {
                            same = false;
                            break;
                        }
                    }
                }
                return same;
            }
        }

        #endregion

        #region Update Methods

        public void Clear()
        {
            TextList.Clear();
        }

        /// <summary>
        /// Place given text for all languages.
        /// </summary>
        /// <param name="textAllLanguage"></param>
        public void UpdateDefaultText(string textAllLanguage)
        {
            listText.Clear();
            foreach (string lg in LangSupport.SupportedLanguages)
                listText.Add(new TextType(lg, textAllLanguage));
        }

        public void UpdateForCurrentLanguage(string text)
        {
            UpdateForLanguage(LangSupport.CurLang, text);
        }
 
        public void UpdateForLanguage(string lang, string text)
        {
            string textContent = text == UndefinedText ? string.Empty : text;
            foreach (TextType t in listText)
                if (t.Language == lang)
                {
                    t.Text = textContent;
                    return;
                }

            // Create
            TextType tx = new TextType(lang, textContent);
            listText.Add(tx);
        }
        #endregion // Update Methods

        #region XML Serialize

        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            if (!IsEmpty)
            {
                if (SdmxNamespaceManager.SdmxTarget == SdmxVersion.SDMX_21 && prefix == "structure")
                    prefix = "common";
                    
                // All same write one tag without lang attribute
                if (AllSame && TextCompression.Compress)
                    xw.WriteElementString(prefix, tag, null, listText[0].Text);
                else
                {
                    foreach (TextType t in listText)
                    {
                        if (t.Text != string.Empty)
                        {
                            xw.WriteStartElement(prefix, tag, null);
                            xw.WriteAttributeString("xml", "lang", null, t.Language);
                            xw.WriteString(t.Text);
                            xw.WriteEndElement();
                        }
                    }
                }
            }
        }

        #endregion

        #region Language retrival

        public string GetForLanguage(string lang, string defaultText)
        {
            string text = defaultText == null ? string.Empty : defaultText;
            foreach (TextType t in listText)
                if (t.Language == lang)
                    return t.Text;
            return text;
        }

        public string GetForLanguage(string lang)
        {
            string text = UndefinedText;
            foreach (TextType t in listText)
                if (t.Language == lang)
                    return t.Text;
            return text;
        }

        public string GetIfDefinedForLanguage(string lang)
        {
            string text = string.Empty;
            foreach (TextType t in listText)
                if (t.Language == lang)
                    return t.Text;
            return text;
        }

        public string GetFirst()
        {
            string text = string.Empty;
            foreach (TextType t in listText)
                if (t.Text.Length > 0)
                    return t.Text;
            return text;
        }

        #endregion

        #region String Representation

        public override string ToString()
        {            
            return GetForLanguage(LangSupport.CurLang);
        }
        #endregion

        public bool SameAs(MultiLang ml)
        {
            bool same = false;
            if (ml != null)
            {
                same = true;
                foreach (string lg in LangSupport.SupportedLanguages)
                    if (ml.GetForLanguage(lg).CompareTo(GetForLanguage(lg)) != 0)
                    {
                        same = false;
                        break;
                    }

            }

            return same;
        }

    }
}
